#include "StdAfx.h"
#include "Camera.h"
#include "TranslationManager.h"


CTranslationManager::CTranslationManager(void)
{
	m_bLocked = false;
	m_pCamera = NULL;
}

CTranslationManager::CTranslationManager(const CCamera* const pCamera){
	m_bLocked = false;
	m_pCamera	= (CCamera*)pCamera;
}
CTranslationManager::~CTranslationManager(void)
{
}
void CTranslationManager::setPlane(const CPlane& plane){
	CVector3D cpNormal = plane.getNormal();
	CVector3D vpNormal = m_pCamera->getVPNVector();
	if(cpNormal.dotProduct(vpNormal) < SMALL_NUM){
		//the constraint plane is perpendicular to the viewing plane
		//=> can move only along line
		
		//1. Change plane:
		m_plane		= CPlane(plane.getPosition(), vpNormal);
		//2. Change line
		CVector3D dirVector = cpNormal.crossProduct(vpNormal);
		m_line		= CRay(plane.getPosition(), dirVector);
		//3. set to move along line
		m_transType = TRANS_ALONG_LINE;	
	}
	else{
		m_plane		= plane;
		m_transType	= TRANS_ON_PLANE;
	}
	m_bLocked = false;
}
const CPlane& CTranslationManager::getPlane(){
	return m_plane;
}
bool CTranslationManager::setLine(const CRay& line){
	CVector3D vpNormal = m_pCamera->getVPNVector();
	CVector3D dirVector = line.getDirection();
	CVector3D cross = vpNormal.crossProduct(dirVector);
	if(cross.getNorm() < SMALL_NUM){
		m_bLocked = true;
		return false;
		//the constraint line is perpendicular to the viewing plane
	}
	else{
		CVector3D camUpVector		= m_pCamera->getUpVector();
		CVector3D camRightVector	= m_pCamera->getRightVector();
		CVector3D cpNormal;

		float withUp	= dirVector.crossProduct(camUpVector).getNorm();
		float withRight = dirVector.crossProduct(camRightVector).getNorm();
		if(withUp > withRight){
			cpNormal		= dirVector.crossProduct(camUpVector);
		}
		else{
			cpNormal		= dirVector.crossProduct(camRightVector);
		}

		m_plane = CPlane(line.getPosition(), cpNormal);
		m_line = line;
		m_transType	= TRANS_ALONG_LINE;

		return true;
	}

}
const CRay& CTranslationManager::getLine(){
	return m_line;
}
void CTranslationManager::setCamera(const CCamera* const pCamera){
	m_pCamera = (CCamera*)pCamera;
}
const CCamera* const CTranslationManager::getCamera(){
	return m_pCamera;
}

//
void CTranslationManager::startFrom(int mouseX, int mouseY){
	float winX, winY, winZ;
	int *viewport;
	double posX, posY, posZ;

	viewport = (int*)m_pCamera->getViewport();
	winX = (float)mouseX;
	winY = (float)viewport[3] - (float)mouseY;

	glReadBuffer( GL_BACK );
	glReadPixels( int(winX), int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
	gluUnProject( 
		winX, winY, winZ, 
		m_pCamera->getModelViewMatrix(), 
		m_pCamera->getProjectionMatrix(),
		m_pCamera->getViewport(), &posX, &posY, &posZ);

	m_plane.setPosition(CPoint3D(posX, posY, posZ));
	m_line.setPosition(CPoint3D(posX, posY, posZ));

	m_curPoint.setCoords(posX, posY, posZ);
	m_prevPoint.setCoords(posX, posY, posZ);

}
CVector3D CTranslationManager::moveTo(int mouseX, int mouseY){
	if(m_bLocked) return CVector3D(0, 0, 0); //can not move

	float winX, winY, winZ0, winZ1;
	int *viewport;
	double posX0, posY0, posZ0;
	double posX1, posY1, posZ1;

	viewport = (int*)m_pCamera->getViewport();
	winX = (float)mouseX;
	winY = (float)viewport[3] - (float)mouseY;
	winZ0 = 0.0f;
	winZ1 = 1.0f;

	glReadBuffer( GL_BACK );
	gluUnProject( 
		winX, winY, winZ0, 
		m_pCamera->getModelViewMatrix(), 
		m_pCamera->getProjectionMatrix(),
		m_pCamera->getViewport(), &posX0, &posY0, &posZ0);
	gluUnProject( 
		winX, winY, winZ1, 
		m_pCamera->getModelViewMatrix(), 
		m_pCamera->getProjectionMatrix(),
		m_pCamera->getViewport(), &posX1, &posY1, &posZ1);
	
	//create projection ray
	m_projRay = CRay(CPoint3D(posX0, posY0, posZ0), CPoint3D(posX1, posY1, posZ1));
	//determine intersection point with the constraint plane
	CPoint3D  intersection;
	m_projRay.intersects(m_plane, intersection);
	m_transVector = intersection - m_curPoint;

	//change the intersection if needed
	CVector3D dirVector = m_line.getDirection();
	dirVector.normalize();
	if(m_transType == TRANS_ALONG_LINE){
		float projOnLine = m_transVector.dotProduct(dirVector);
		intersection = m_curPoint + projOnLine*dirVector;
		m_transVector = intersection - m_curPoint;
	}
	m_curPoint = intersection;
	//
	m_line.setPosition(intersection);
	m_plane.setPosition(intersection);
	//
	return m_transVector;
}
